const Express = require('express')
const fs = require('fs')
const path = require('path')
const isTest = process.env.NODE_ENV === 'test' || !!process.env.VITE_TEST_BUILD
const serialize = require('serialize-javascript');

async function createServer(
  root = process.cwd(),
  isProd = process.env.NODE_ENV === 'production'
) {
  try {
    const resolve = (p) => path.resolve(__dirname, p)

    const indexProd = isProd
      ? fs.readFileSync(resolve('../dist/client/index.html'), 'utf-8')
      : ''

    const manifest = isProd
      ? // @ts-ignore
      require(resolve('../dist/client/ssr-manifest.json'))
      : {}

    const app = new Express()

    /**
     * @type {import('vite').ViteDevServer}
     */
    let vite
    if (!isProd) {
      vite = await require('vite').createServer({
        root,
        logLevel: isTest ? 'error' : 'info',
        server: {
          middlewareMode: 'ssr',
          watch: {
            // During tests we edit the files too fast and sometimes chokidar
            // misses change events, so enforce polling for consistency
            usePolling: true,
            interval: 100
          }
        }
      })
      app.use(vite.middlewares)
      // const middlewares = compose([main, vite.middlewares])
      // app.use(middlewares)
    } else {
      app.use(require('compression')())
      app.use(
        require('serve-static')(resolve('dist/client'), {
          index: false
        })
      )
    }

    app.use("*", async (req, res) => {
      try {
        const url = req.originalUrl
        let template, render
        if (!isProd) {
          template = fs.readFileSync(resolve('../index.html'), 'utf-8')
          template = await vite.transformIndexHtml(url, template)
          render = (await vite.ssrLoadModule(resolve('../src/entry-server.js'))).render
        } else {
          template = indexProd
          render = require('../dist/server/entry-server.js').render
        }
        // 调用服务端渲染方法，将vue组件渲染成dom结构，顺带分析出需要预加载的js，css等文件。
        const [appHtml, preloadLinks, store] = await render(url, manifest)
        // 新加 + 将服务端预取数据的store，插入html模板文件
        const state = ("<script>window.__INIT_STATE__" + "=" + serialize(store.state, { isJSON: true }) + "</script>");
        // 把html中的展位符替换成相对应的资源文件
        const html = template
          .replace(`<!--preload-links-->`, preloadLinks)
          .replace(`<!--app-html-->`, appHtml)
          .replace(`<!--app-store-->`, state)

        res.status(200).set({ 'Content-Type': 'text/html' }).end(html)
      } catch (error) {
        vite && vite.ssrFixStacktrace(e)
        console.log(e.stack)
        res.status(500).end(e.stack)
      }
    })

    return { app, vite }
  } catch (error) {
    console.log(error);
  }
}
// 创建node服务器用作ssr
if (!isTest) {
  createServer().then(({ app }) =>
    app.listen(3001, () => {
      console.log('http://localhost:3001')
    })
  )
}

// for test use
exports.createServer = createServer
